package org.ecloud.oauth.client.filter;

import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.ecloud.common.constants.StateEnum;
import org.ecloud.common.constants.StringPool;
import org.ecloud.core.entity.APIResult;
import org.ecloud.oauth.constants.GrantType;
import org.ecloud.oauth.constants.ParameterKey;
import org.ecloud.oauth.constants.RedisKey;
import org.ecloud.utils.JacksonUtil;
import org.ecloud.utils.StringUtil;

public class AccessTokenFilter extends AbstractFilter {

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		HttpServletResponse httpResponse = (HttpServletResponse) response;

		logger.debug("oauth client access token filter, request path {}.", httpRequest.getRequestURI());
		logger.debug("enable is {}.", authorizationConfig.isEnable());// NullExceptionPoint
		logger.debug("requestType is {}.", authorizationConfig.getRequestType());
		logger.debug("ignoreUrls has {}.", JacksonUtil.toJsonString(authorizationConfig.getIgnoreUrls()));
		
		Enumeration<String> headers = httpRequest.getHeaderNames();
		if(headers.hasMoreElements()){
			String headerName = headers.nextElement();
			logger.debug("header {} is {}.", headerName, httpRequest.getHeader(headerName));
		}
		
		// 地址忽略
		if(!authorizationConfig.isEnable() || authorizationConfig.getIgnoreUrls().contains(httpRequest.getRequestURI())){
			logger.debug("requestURI {} is ignore.", httpRequest.getRequestURI());
			chain.doFilter(request, response);
			return;
		}
		
		// 上下文获取，防止无限循环
		String contextHeader = httpRequest.getHeader(ParameterKey.HEADER_CONTEXT);
		logger.debug("header {} is {}.", ParameterKey.HEADER_CONTEXT, contextHeader);
		if(StringUtil.isNotBlank(contextHeader)){
			logger.debug("context requestURI {} is ignore.", httpRequest.getRequestURI());
			chain.doFilter(request, response);
			return;
		}
		
		httpRequest.setCharacterEncoding(StringPool.UTF_8);
		response.setCharacterEncoding(StringPool.UTF_8);
		String accessTokenHeader = httpRequest.getHeader(ParameterKey.HEADER_AUTHORIZATION);
	    String accessTokenParameter = httpRequest.getParameter(ParameterKey.PARAMETER_ACCESS_TOKEN);
	    logger.debug("header {} is {}.", ParameterKey.HEADER_AUTHORIZATION, accessTokenHeader);
	    logger.debug("parameter {} is {}.", ParameterKey.PARAMETER_ACCESS_TOKEN, accessTokenParameter);
	    
	    String accessToken = StringUtil.isBlank(accessTokenHeader) ? (StringUtil.isBlank(accessTokenParameter) ? null : accessTokenParameter) : accessTokenHeader;
	    
	    if(StringUtil.isBlank(accessToken)){
	    	APIResult<Void> result = new APIResult<>();
	    	result.setCode(StateEnum.ILLEGAL_TOKEN.getCode());
	    	result.setCause(StateEnum.ILLEGAL_TOKEN.getText());
	    	
	    	logger.error(StateEnum.ILLEGAL_TOKEN.getText());
	    	httpResponse.setStatus(401);
	    	httpResponse.getWriter().print(result.toString());
	    } else {
	    	try {
	    		APIResult<String> tokenResult = verify(accessToken);
	    		
	    		if(StateEnum.SUCCESS.getCode() == tokenResult.getCode()){
	    			String grantType = tokenResult.getVariable(RedisKey.GRANT_TYPE).toString();
	    			String value = tokenResult.getData();
	    			
	    			logger.debug("grant type is {}.", grantType);
	    			logger.debug("value is {}.", value);
	    			
	    			if(GrantType.AUTHORIZATION_CODE.equalsIgnoreCase(grantType)
	    					|| GrantType.PASSWORD_CREDENTIALS.equalsIgnoreCase(grantType)){
	    				// 校验通过，设置上下文
	    				setContext(httpRequest, accessToken, value);
	    			} else {
	    				logger.warn("This grant type {} not have user info.");
	    			}
	    			
	    			// 执行下一个filter
	    			chain.doFilter(request, response);
	    		} else {
	    			response.getWriter().print(tokenResult.toString());
	    		}
			} catch (Exception e) {
				APIResult<Void> result = new APIResult<>();
		    	result.setCode(StateEnum.ILLEGAL_REQUEST.getCode());
		    	result.setCause(e.getMessage());
		    	
		    	logger.error(e.getMessage(), e);
		    	httpResponse.setStatus(401);
		    	httpResponse.getWriter().print(result.toString());
			}
	    }
	}

}
